1、题干
如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串。
花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串,定义下面几条语法规则:
- 如果只给出单一的元素 
x,那么表达式表示的字符串就只有"x"。R(x) = {x}- 例如,表达式 
"a"表示字符串"a"。 - 而表达式 
"w"就表示字符串"w"。 
 - 例如,表达式 
 - 当两个或多个表达式并列,以逗号分隔,我们取这些表达式中元素的并集。
R({e_1,e_2,...}) = R(e_1) ∪ R(e_2) ∪ ...- 例如,表达式 
"{a,b,c}"表示字符串"a","b","c"。 - 而表达式 
"{{a,b},{b,c}}"也可以表示字符串"a","b","c"。 
 - 例如,表达式 
 - 要是两个或多个表达式相接,中间没有隔开时,我们从这些表达式中各取一个元素依次连接形成字符串。
R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)}- 例如,表达式 
"{a,b}{c,d}"表示字符串"ac","ad","bc","bd"。 
 - 例如,表达式 
 - 表达式之间允许嵌套,单一元素与表达式的连接也是允许的。
- 例如,表达式 
"a{b,c,d}"表示字符串"ab","ac","ad"。 - 例如,表达式 
"a{b,c}{d,e}f{g,h}"可以表示字符串"abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", "acefg", "acefh"。 
 - 例如,表达式 
 
给出表示基于给定语法规则的表达式 expression,返回它所表示的所有字符串组成的有序列表。
假如你希望以「集合」的概念了解此题,也可以通过点击 “显示英文描述” 获取详情。
示例 1:
输入:expression = "{a,b}{c,{d,e}}"
输出:["ac","ad","ae","bc","bd","be"]示例 2:
输入:expression = "{{a,z},a{b,c},{ab,z}}"
输出:["a","ab","ac","z"]
解释:输出中 不应 出现重复的组合结果。
提示:
1 <= expression.length <= 60expression[i]由'{','}',','或小写英文字母组成- 给出的表达式 
expression用以表示一组基于题目描述中语法构造的字符串 
2、思路
本题要处理的子表达式主要包括3类:
- 单层:
{xxx,xxx} - 嵌套:
{{xxx},{xxx}} - 相接:
{xxx}{xxx},xxx{xxx},{xxx}xxx 
具体代码实现逻辑如下:
- 扁平化:把最内层的单层表达式提取到上一层(这会逐渐把嵌套和单层表达式都处理掉)
 - 拼接组合:拼接组合最内层相接子表达式
 - 重复这两个步骤直到表达式中没有任何花括号
 - 最后对表达式进行拆分、去重、排序
 
3、代码
function braceExpansionII(exp: string): string[] {
    const reg0 = /\{([a-z,]+)\}/g;
    const reg1 = new RegExp(`(?<![a-z}])${reg0.source}(?![a-z{])`, 'g');
    const reg2 = new RegExp(`(${reg0.source}){2,}|[a-z]+(${reg0.source})+|(${reg0.source})+[a-z]+`, 'g');
    while (1) {
        const f1 = reg1.test(exp);
        if (f1) exp = exp.replace(reg1, '$1');
        const f2 = reg2.test(exp);
        if (f2) {
            exp = exp.replace(reg2, (m) => {
                const reg = new RegExp(`${reg0.source}|[a-z]+`, 'g');
                const tokenGroup = (m.match(reg) || []).map(s => s.split(/,|\{|\}/).filter(Boolean));
                let ans = tokenGroup[0];
                for (let i = 1; i < tokenGroup.length; i++) {
                    const newAns = [];
                    for (const h of ans) {
                        for (const t of tokenGroup[i]) {
                            newAns.push(h + t);
                        }
                    }
                    ans = newAns;
                }
                return `{${ans.join(',')}}`
            });
        }
        if (!f1 && !f2) break;
    }
    return [...new Set(exp.split(','))].sort();
};
4、执行结果
